package com.komeri.komeriapl;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Point;
import android.hardware.Camera;
import android.os.Build;
import android.util.Log;
import android.view.Display;
import android.view.WindowManager;
import java.util.regex.Pattern;

/**
 * カメラ配置管理
 * @author Liu Mingjia
 * */
final class CameraConfigurationManager {

  private static final String TAG = CameraConfigurationManager.class.getSimpleName();

  private static final int TEN_DESIRED_ZOOM = 27;
  private static final int DESIRED_SHARPNESS = 30;

  private static final Pattern COMMA_PATTERN = Pattern.compile(",");

  private final Context context;
  
  /**スクリーン解像度*/
  private Point screenResolution;
  /**カメラ解像度*/
  private Point cameraResolution;
  private int previewFormat;
  private String previewFormatString;

  CameraConfigurationManager(Context context) {
	  
    this.context = context;
  }

  /**
   * Reads, one time, values from the camera that are needed by the app.
   * @param camera
   */
  void initFromCameraParameters(Camera camera) {
	  
    Camera.Parameters parameters = camera.getParameters();
    
    previewFormat = parameters.getPreviewFormat();
    
    previewFormatString = parameters.get("preview-format");
    
    WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
    
    Display display = manager.getDefaultDisplay();
    
    screenResolution = new Point(display.getWidth(), display.getHeight());
    
    cameraResolution = getCameraResolution(parameters, screenResolution);
  }

  /**
   * Sets the camera up to take preview images which are used for both preview and decoding.
   * We detect the preview format here so that buildLuminanceSource() can build an appropriate
   * LuminanceSource subclass. In the future we may want to force YUV420SP as it's the smallest,
   * and the planar Y can be used for barcode scanning without a copy in some cases.
   */
  @SuppressLint("NewApi")
void setDesiredCameraParameters(Camera camera) {

    Camera.Parameters parameters = camera.getParameters();
    
    parameters.setPreviewSize(cameraResolution.x, cameraResolution.y);
    
    setFlash(parameters);
    
    setZoom(parameters);
    
    //スクリーンを縦ディスプレイに設置する	
    camera.setDisplayOrientation(90);
    
    camera.setParameters(parameters);
  }

  /**
   * カメラの解像度を取得する
   * */
  Point getCameraResolution() {
    return cameraResolution;
  }

  /**
   * スクリーンの解像度を取得する
   * */
  Point getScreenResolution() {
    return screenResolution;
  }
  
  /**
   * カメラ初期化の設置を取得する
   * */
  int getPreviewFormat() {
    return previewFormat;
  }

  String getPreviewFormatString() {
    return previewFormatString;
  }

  /**
   * 調整後のカメラ解像度を取得する
   * @param parameters
   * @param screenResolution
   * */
  private static Point getCameraResolution(Camera.Parameters parameters, Point screenResolution){
	  
    String previewSizeValueString = parameters.get("preview-size-values");
    
    // saw this on Xperia
    if (previewSizeValueString == null) {
    	
        previewSizeValueString = parameters.get("preview-size-value");
    }

    Point cameraResolution = null;

    if (previewSizeValueString != null) {
    	
      cameraResolution = findBestPreviewSizeValue(previewSizeValueString, screenResolution);
    }

    if (cameraResolution == null) {
    	
      // Ensure that the camera resolution is a multiple of 8, as the screen may not be.
      cameraResolution = new Point(
          (screenResolution.x >> 3) << 3,
          (screenResolution.y >> 3) << 3);
    }
    return cameraResolution;
  }

  /***
   * 適合のスクリーン解像度を取得する
   * @param previewSizeValueString
   * @param screenResolution
   * */
  private static Point findBestPreviewSizeValue(CharSequence previewSizeValueString,
          Point screenResolution) {
	  
      int bestX = 0;
      int bestY = 0;
      int diff = Integer.MAX_VALUE;
      
      for (String previewSize : COMMA_PATTERN.split(previewSizeValueString)) {
    	  
          previewSize = previewSize.trim();
          
          int dimPosition = previewSize.indexOf('x');
          
          if (dimPosition < 0) {
        	  
        	  continue;
          }

      int newX;
      int newY;

      try {
        newX = Integer.parseInt(previewSize.substring(0, dimPosition));
        newY = Integer.parseInt(previewSize.substring(dimPosition + 1));
      } catch (NumberFormatException nfe) {
        Log.w(TAG, "Bad preview-size: " + previewSize);
        continue;
      }

      int newDiff = Math.abs(newX - screenResolution.x) + Math.abs(newY - screenResolution.y);
      
      if (newDiff == 0) {
    	  
        bestX = newX;
        bestY = newY;
        break;
      } else if (newDiff < diff) {
    	  
        bestX = newX;
        bestY = newY;
        diff = newDiff;
      }
    }

    if (bestX > 0 && bestY > 0) {
    	
        return new Point(bestX, bestY);
    }
    return null;
  }

  /**
   * 適合なズーム比を計算する
   * @param stringValues
   * @param tenDesiredZoom
   * */
  private static int findBestMotZoomValue(CharSequence stringValues, int tenDesiredZoom) {
	  
    int tenBestValue = 0;
    
    for (String stringValue : COMMA_PATTERN.split(stringValues)) {
    	
        stringValue = stringValue.trim();
      
        double value;
      
        try {
    	  
            value = Double.parseDouble(stringValue);
        
        } catch (NumberFormatException nfe) {
    	  
            return tenDesiredZoom;
        }
      
        int tenValue = (int) (10.0 * value);
      
        if (Math.abs(tenDesiredZoom - value) < Math.abs(tenDesiredZoom - tenBestValue)) {
    	  
            tenBestValue = tenValue;
        }
    }
    return tenBestValue;
  }

  /**
   * エレクトロニックフラッシュを設置、デフォルト状態は閉める
   * @param parameters
   * */
  private void setFlash(Camera.Parameters parameters) {

      if (Build.MODEL.contains("Behold II") && CameraManager.SDK_INT == 3) { 
    	
          parameters.set("flash-value", 1);
        
      } else {
          parameters.set("flash-value", 2);
      }
      
      // This is the standard setting to turn the flash off that all devices should honor.
      parameters.set("flash-mode", "off");
  }

  /**
   * カメラのプレービューを調整する時に、JANコードの最優ズーム比に調整する
   * @param parameters
   * */
  private void setZoom(Camera.Parameters parameters) {

      String zoomSupportedString = parameters.get("zoom-supported");
    
      if (zoomSupportedString != null && !Boolean.parseBoolean(zoomSupportedString)) {
          return;
      }

      int tenDesiredZoom = TEN_DESIRED_ZOOM;

      String maxZoomString = parameters.get("max-zoom");
    
      if (maxZoomString != null) {
    	  
          try {
        	  
              int tenMaxZoom = (int) (10.0 * Double.parseDouble(maxZoomString));
              
              if (tenDesiredZoom > tenMaxZoom) {
            	  
                  tenDesiredZoom = tenMaxZoom;
              }
          } catch (NumberFormatException nfe) {
        	  
              Log.w(TAG, "Bad max-zoom: " + maxZoomString);
          }
      }

      String takingPictureZoomMaxString = parameters.get("taking-picture-zoom-max");
      
      if (takingPictureZoomMaxString != null) {
    	  
          try {
        	  
              int tenMaxZoom = Integer.parseInt(takingPictureZoomMaxString);
          
              if (tenDesiredZoom > tenMaxZoom) {
        	  
                  tenDesiredZoom = tenMaxZoom;
              }
          
          }catch (NumberFormatException nfe) {
        	  
              Log.w(TAG, "Bad taking-picture-zoom-max: " + takingPictureZoomMaxString);
          }
      }

      String motZoomValuesString = parameters.get("mot-zoom-values");
      
      if (motZoomValuesString != null) {
    	  
          tenDesiredZoom = findBestMotZoomValue(motZoomValuesString, tenDesiredZoom);
      }

      String motZoomStepString = parameters.get("mot-zoom-step");
      
      if (motZoomStepString != null) {
          try {
        	  
              double motZoomStep = Double.parseDouble(motZoomStepString.trim());
              
              int tenZoomStep = (int) (10.0 * motZoomStep);
              
              if (tenZoomStep > 1) {
            	  
                  tenDesiredZoom -= tenDesiredZoom % tenZoomStep;
              }
          } catch (NumberFormatException nfe) {
        	    
        	  Log.w("CameraConfigurationManager", "setZoom");
          }
      }

    // Set zoom. This helps encourage the user to pull back.
    // Some devices like the Behold have a zoom parameter
    if (maxZoomString != null || motZoomValuesString != null) {
    	
      parameters.set("zoom", String.valueOf(tenDesiredZoom / 10.0));
    }

    // Most devices, like the Hero, appear to expose this zoom parameter.
    // It takes on values like "27" which appears to mean 2.7x zoom
    if (takingPictureZoomMaxString != null) {
    	
      parameters.set("taking-picture-zoom", tenDesiredZoom);
    }
  }

	public static int getDesiredSharpness() {
		return DESIRED_SHARPNESS;
	}

}
